/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package uk.ac.cam.juliet.zedcat.client;

import java.io.*;
import java.net.*;
/**
 *
 * @author Chris
 */

public class HTTPPost {

	private static final String NEWLINE = "\r\n";
        // used to prefix the boundary
	private static final String PREFIX = "--";

	private DataOutputStream out = null;

	// breaks up fields
	private String boundary = null;

	// Takes a stream and a boundary setting and makes a new HTTPPost that data can be added to.
	public HTTPPost(OutputStream os, String boundary) {
		if(os == null) {
			throw new IllegalArgumentException("Output stream is required.");
		}
		if(boundary == null || boundary.length() == 0) {
			throw new IllegalArgumentException("Boundary stream is required.");
		}
		this.out = new DataOutputStream(os);
		this.boundary = boundary;
	}

        private void prefix() throws java.io.IOException {
            out.writeBytes(PREFIX);
        }

        private void newline() throws java.io.IOException {
            out.writeBytes(NEWLINE);
        }

	public void writeField(String name, String value) throws java.io.IOException {
		if(name == null) {
			throw new IllegalArgumentException("Name cannot be null or empty.");
		}
		if(value == null) {
			value = "";
		}
		/*
		--boundary\r\n
		Content-Disposition: form-data; name="<fieldName>"\r\n
		\r\n
		<value>\r\n
		*/
		// write boundary
		prefix();
		out.writeBytes(boundary);
		newline();
		// write content header
		out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
		newline();
		newline();
		// write content
		out.writeBytes(value);
		newline();
		out.flush();
	}

	// Wrapper for WriteFile with an input stream.
	public void writeFile(String name, String mimeType, File file) throws java.io.IOException {
		if(file == null) {
			throw new IllegalArgumentException("File cannot be null.");
		}
		if(!file.exists()) {
			throw new IllegalArgumentException("File does not exist.");
		}
		if(file.isDirectory()) {
			throw new IllegalArgumentException("File cannot be a directory.");
		}
		writeFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(file));
	}

	// Take a field name, mimetype, and then the filename and an inputstream.
        // Writes the file into the output stream with correct content markers and boundary.
	public void writeFile(String name, String mimeType, String fileName, InputStream is)
			throws java.io.IOException {
		if(is == null) {
			throw new IllegalArgumentException("Input stream cannot be null.");
		}
		if(fileName == null || fileName.length() == 0) {
			throw new IllegalArgumentException("File name cannot be null or empty.");
		}
		/*
		--boundary\r\n
		Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
		Content-Type: <mime-type>\r\n
		\r\n
		<file-data>\r\n
		*/
		// write boundary
		prefix();
		out.writeBytes(boundary);
		newline();
		// write content header
		out.writeBytes("Content-Disposition: form-data; name=\"" + name +
			"\"; filename=\"" + fileName + "\"");
		newline();
		if(mimeType != null) {
			out.writeBytes("Content-Type: " + mimeType);
			newline();
		}
		newline();
		// write content
		byte[] data = new byte[1024];
		int r = 0;
		while((r = is.read(data, 0, data.length)) != -1) {
			out.write(data, 0, r);
		}
		// close input stream, but ignore any possible exception for it
		try {
			is.close();
		} catch(Exception e) {}
		out.writeBytes(NEWLINE);
		out.flush();
	}

	// Write the last boundary and close the stream.
	public void close() throws java.io.IOException {
		// write final boundary
		prefix();
		out.writeBytes(boundary);
		prefix();
		newline();
		out.flush();
		out.close();
	}
        // Return the boundary used.
	public String getBoundary() {
		return this.boundary;
	}

	// Creates a connection suitable for POSTing on.
	public static URLConnection createConnection(URL url) throws java.io.IOException {
		URLConnection urlConn = url.openConnection();
		if(urlConn instanceof HttpURLConnection) {
			HttpURLConnection httpConn = (HttpURLConnection)urlConn;
			httpConn.setRequestMethod("POST");
		}
		urlConn.setDoInput(true);
		urlConn.setDoOutput(true);
		urlConn.setUseCaches(false);
		urlConn.setDefaultUseCaches(false);
		return urlConn;
	}

	// Create a boundary from the current time.
	public static String createBoundary() {
		return "--------------------" +
			Long.toString(System.currentTimeMillis(), 16);
	}

	// We need to set the content type before we create the OutputStream that the constructor
        // Uses, so we need a static method to create a proper content type.
	public static String getContentType(String boundary) {
		return "multipart/form-data; boundary=" + boundary;
	}
}